﻿Imports System
Imports System.Collections.Generic
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.ComponentModel
    Friend Class CompensationUtils
        ' Methods
        Private Shared Function CollectCompensatableActiveContexts(ByVal context As ActivityExecutionContext, ByVal targetActivity As Activity, ByVal sortedListOfCompensatableTargets As SortedDictionary([Of] Integer, CompensationInfo), ByVal immediateCompensation As Boolean) As Boolean
            Dim context2 As ActivityExecutionContext
            For Each context2 In context.ExecutionContextManager.ExecutionContexts
                If ((targetActivity.GetActivityByName(context2.Activity.QualifiedName, True) Is Nothing) OrElse (immediateCompensation AndAlso CompensationUtils.IsActivityInBackWorkBranch(targetActivity, context2.Activity))) Then
                    [Continue] For
                End If
                If (TypeOf context2.Activity Is ICompensatableActivity AndAlso (((context2.Activity.ExecutionStatus = ActivityExecutionStatus.Compensating) OrElse (context2.Activity.ExecutionStatus = ActivityExecutionStatus.Faulting)) OrElse (context2.Activity.ExecutionStatus = ActivityExecutionStatus.Canceling))) Then
                    Return True
                End If
                If TypeOf context2.Activity Is CompositeActivity Then
                    Dim compensatableChildren As Activity() = CompensationUtils.GetCompensatableChildren([TryCast](context2.Activity,CompositeActivity))
                    If (Not compensatableChildren Is Nothing) Then
                        Dim key As Integer = 0
                        Dim activity As Activity
                        For Each activity In compensatableChildren
                            Dim num2 As Integer = CInt(activity.GetValue(Activity.CompletedOrderIdProperty))
                            If (key < num2) Then
                                key = num2
                            End If
                        Next
                        If (key <> 0) Then
                            sortedListOfCompensatableTargets.Add(key, New CompensationInfo(context2))
                        End If
                    End If
                    CompensationUtils.CollectCompensatableActiveContexts(context2, targetActivity, sortedListOfCompensatableTargets, immediateCompensation)
                    CompensationUtils.CollectCompensatableCompletedContexts(context2, targetActivity, sortedListOfCompensatableTargets, immediateCompensation)
                End If
            Next
            Return False
        End Function

        Private Shared Sub CollectCompensatableCompletedContexts(ByVal context As ActivityExecutionContext, ByVal targetActivity As Activity, ByVal sortedListOfCompensatableTargets As SortedDictionary([Of] Integer, CompensationInfo), ByVal immediateCompensation As Boolean)
            Dim executionContextManager As ActivityExecutionContextManager = context.ExecutionContextManager
            Dim i As Integer = (executionContextManager.CompletedExecutionContexts.Count - 1)
            Do While (i >= 0)
                Dim targetExecutionInfo As ActivityExecutionContextInfo = executionContextManager.CompletedExecutionContexts.Item(i)
                If (CByte((targetExecutionInfo.Flags And PersistFlags.NeedsCompensation)) <> 0) Then
                    Dim activityByName As Activity = targetActivity.GetActivityByName(targetExecutionInfo.ActivityQualifiedName, True)
                    If ((Not activityByName Is Nothing) AndAlso (Not immediateCompensation OrElse Not CompensationUtils.IsActivityInBackWorkBranch(targetActivity, activityByName))) Then
                        sortedListOfCompensatableTargets.Add(targetExecutionInfo.CompletedOrderId, New CompensationInfo(targetExecutionInfo, executionContextManager))
                    End If
                End If
                i -= 1
            Loop
        End Sub

        Private Shared Function CollectCompensatableTargetActivities(ByVal compositeActivity As CompositeActivity, ByVal sortedListOfCompensatableTargets As SortedDictionary([Of] Integer, CompensationInfo), ByVal immediateCompensation As Boolean) As Boolean
            Dim queue As New Queue([Of] Activity)(Helpers.GetAllEnabledActivities(compositeActivity))
            Do While (queue.Count > 0)
                Dim childActivity As Activity = queue.Dequeue
                If (((childActivity.ExecutionStatus = ActivityExecutionStatus.Compensating) OrElse (childActivity.ExecutionStatus = ActivityExecutionStatus.Faulting)) OrElse (childActivity.ExecutionStatus = ActivityExecutionStatus.Canceling)) Then
                    Return True
                End If
                If (Not immediateCompensation OrElse Not CompensationUtils.IsActivityInBackWorkBranch(compositeActivity, childActivity)) Then
                    If ((TypeOf childActivity Is ICompensatableActivity AndAlso (childActivity.ExecutionStatus = ActivityExecutionStatus.Closed)) AndAlso (childActivity.ExecutionResult = ActivityExecutionResult.Succeeded)) Then
                        sortedListOfCompensatableTargets.Add(CInt(childActivity.GetValue(Activity.CompletedOrderIdProperty)), New CompensationInfo(childActivity))
                    ElseIf TypeOf childActivity Is CompositeActivity Then
                        Dim activity2 As Activity
                        For Each activity2 In Helpers.GetAllEnabledActivities(DirectCast(childActivity, CompositeActivity))
                            queue.Enqueue(activity2)
                        Next
                        [Continue] Do
                    End If
                End If
            Loop
            Return False
        End Function

        Private Shared Sub CompleteRevokedExecutionContext(ByVal targetActivity As Activity, ByVal context As ActivityExecutionContext)
            Dim array As ActivityExecutionContext() = New ActivityExecutionContext(context.ExecutionContextManager.ExecutionContexts.Count  - 1) {}
            context.ExecutionContextManager.ExecutionContexts.CopyTo(array, 0)
            Dim context2 As ActivityExecutionContext
            For Each context2 In array
                If (Not targetActivity.GetActivityByName(context2.Activity.QualifiedName, True) Is Nothing) Then
                    If (context2.Activity.ExecutionStatus = ActivityExecutionStatus.Closed) Then
                        CompensationUtils.CompleteRevokedExecutionContext(context2.Activity, context2)
                    End If
                    context.ExecutionContextManager.CompleteExecutionContext(context2)
                End If
            Next
        End Sub

        Friend Shared Function GetCompensatableChildren(ByVal compositeActivity As CompositeActivity) As Activity()
            Dim dictionary As New SortedDictionary([Of] Integer, Activity)
            Dim queue As New Queue([Of] Activity)(Helpers.GetAllEnabledActivities(compositeActivity))
            Do While (queue.Count > 0)
                Dim activity As Activity = queue.Dequeue
                If ((TypeOf activity Is ICompensatableActivity AndAlso (activity.ExecutionStatus = ActivityExecutionStatus.Closed)) AndAlso (activity.ExecutionResult = ActivityExecutionResult.Succeeded)) Then
                    dictionary.Add(CInt(activity.GetValue(Activity.CompletedOrderIdProperty)), activity)
                ElseIf TypeOf activity Is CompositeActivity Then
                    Dim activity2 As Activity
                    For Each activity2 In Helpers.GetAllEnabledActivities(DirectCast(activity, CompositeActivity))
                        queue.Enqueue(activity2)
                    Next
                    [Continue] Do
                End If
            Loop
            Dim array As Activity() = New Activity(dictionary.Count  - 1) {}
            dictionary.Values.CopyTo(array, 0)
            Return array
        End Function

        Friend Shared Function GetLastCompensatableChild(ByVal compositeActivity As CompositeActivity) As Activity
            Dim compensatableChildren As Activity() = CompensationUtils.GetCompensatableChildren(compositeActivity)
            If (((Not compensatableChildren Is Nothing) AndAlso (compensatableChildren.Length > 0)) AndAlso (Not compensatableChildren((compensatableChildren.Length - 1)) Is Nothing)) Then
                Return compensatableChildren((compensatableChildren.Length - 1))
            End If
            Return Nothing
        End Function

        Private Shared Function IsActivityInBackWorkBranch(ByVal targetParent As Activity, ByVal childActivity As Activity) As Boolean
            Dim parent As Activity = childActivity
            Do While (Not parent.Parent Is targetParent)
                parent = parent.Parent
            Loop
            Return Helpers.IsFrameworkActivity(parent)
        End Function

        Friend Shared Function TryCompensateLastCompletedChildActivity(ByVal context As ActivityExecutionContext, ByVal targetActivity As Activity, ByVal statusChangeHandler As IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs)) As Boolean
            Dim flag As Boolean
            Try 
                flag = CompensationUtils.TryCompensateLastCompletedChildActivity(context, targetActivity, statusChangeHandler, True)
            Catch exception1 As Exception
                If (targetActivity.Parent Is Nothing) Then
                    CompensationUtils.CompleteRevokedExecutionContext(targetActivity, context)
                End If
                Throw
            End Try
            Return flag
        End Function

        Private Shared Function TryCompensateLastCompletedChildActivity(ByVal context As ActivityExecutionContext, ByVal targetActivity As Activity, ByVal statusChangeHandler As IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs), ByVal isimmediateCompensation As Boolean) As Boolean
            Dim sortedListOfCompensatableTargets As New SortedDictionary([Of] Integer, CompensationInfo)
            If TypeOf targetActivity Is CompositeActivity Then
                If CompensationUtils.CollectCompensatableTargetActivities([TryCast](targetActivity,CompositeActivity), sortedListOfCompensatableTargets, isimmediateCompensation) Then
                    Return True
                End If
                If CompensationUtils.CollectCompensatableActiveContexts(context, targetActivity, sortedListOfCompensatableTargets, isimmediateCompensation) Then
                    Return True
                End If
                CompensationUtils.CollectCompensatableCompletedContexts(context, targetActivity, sortedListOfCompensatableTargets, isimmediateCompensation)
                If (sortedListOfCompensatableTargets.Count = 0) Then
                    CompensationUtils.CompleteRevokedExecutionContext(targetActivity, context)
                    Return False
                End If
                Dim nullable As Nullable([Of] Integer) = [TryCast](targetActivity.GetValue(CompensationHandlingFilter.LastCompensatedOrderIdProperty),Nullable([Of] Integer))
                Dim num As Integer = -1
                Dim info As CompensationInfo = Nothing
                Dim num2 As Integer
                For Each num2 In sortedListOfCompensatableTargets.Keys
                    If nullable.HasValue Then
                        Dim nullable2 As Nullable([Of] Integer) = nullable
                        Dim num3 As Integer = num2
                        If ((nullable2.GetValueOrDefault < num3) AndAlso nullable2.HasValue) Then
                            Exit For
                        End If
                    End If
                    info = sortedListOfCompensatableTargets.Item(num2)
                    num = num2
                Next
                If (info Is Nothing) Then
                    CompensationUtils.CompleteRevokedExecutionContext(targetActivity, context)
                    Return False
                End If
                targetActivity.SetValue(CompensationHandlingFilter.LastCompensatedOrderIdProperty, num)
                If ((Not info.TargetActivity Is Nothing) AndAlso TypeOf info.TargetActivity Is ICompensatableActivity) Then
                    info.TargetActivity.RegisterForStatusChange(Activity.StatusChangedEvent, statusChangeHandler)
                    context.CompensateActivity(info.TargetActivity)
                    Return True
                End If
                If ((Not info.TargetExecutionInfo Is Nothing) AndAlso (Not info.TargetExecutionContextManager Is Nothing)) Then
                    Dim context2 As ActivityExecutionContext = info.TargetExecutionContextManager.DiscardPersistedExecutionContext(info.TargetExecutionInfo)
                    If TypeOf context2.Activity Is ICompensatableActivity Then
                        context2.Activity.RegisterForStatusChange(Activity.StatusChangedEvent, statusChangeHandler)
                        context2.CompensateActivity(context2.Activity)
                        Return True
                    End If
                    If TypeOf context2.Activity Is CompositeActivity Then
                        Dim lastCompensatableChild As Activity = CompensationUtils.GetLastCompensatableChild([TryCast](context2.Activity,CompositeActivity))
                        If (Not lastCompensatableChild Is Nothing) Then
                            lastCompensatableChild.RegisterForStatusChange(Activity.StatusChangedEvent, statusChangeHandler)
                            context2.CompensateActivity(lastCompensatableChild)
                            Return True
                        End If
                        Return CompensationUtils.TryCompensateLastCompletedChildActivity(context2, context2.Activity, statusChangeHandler, False)
                    End If
                ElseIf ((Not info.TargetExecutionContext Is Nothing) AndAlso TypeOf info.TargetExecutionContext.Activity Is CompositeActivity) Then
                    Dim activity As Activity = CompensationUtils.GetLastCompensatableChild([TryCast](info.TargetExecutionContext.Activity,CompositeActivity))
                    If (Not activity Is Nothing) Then
                        activity.RegisterForStatusChange(Activity.StatusChangedEvent, statusChangeHandler)
                        info.TargetExecutionContext.CompensateActivity(activity)
                        Return True
                    End If
                    Return CompensationUtils.TryCompensateLastCompletedChildActivity(info.TargetExecutionContext, info.TargetExecutionContext.Activity, statusChangeHandler, False)
                End If
            End If
            Return False
        End Function


        ' Nested Types
        Private NotInheritable Class CompensationInfo
            ' Methods
            Friend Sub New(ByVal targetActivity As Activity)
                Me.targetActivity = targetActivity
            End Sub

            Friend Sub New(ByVal targetExecutionContext As ActivityExecutionContext)
                Me.targetExecutionContext = targetExecutionContext
            End Sub

            Friend Sub New(ByVal targetExecutionInfo As ActivityExecutionContextInfo, ByVal targetExecutionContextManager As ActivityExecutionContextManager)
                Me.targetExecutionInfo = targetExecutionInfo
                Me.targetExecutionContextManager = targetExecutionContextManager
            End Sub


            ' Properties
            Friend ReadOnly Property TargetActivity As Activity
                Get
                    Return Me.targetActivity
                End Get
            End Property

            Friend ReadOnly Property TargetExecutionContext As ActivityExecutionContext
                Get
                    Return Me.targetExecutionContext
                End Get
            End Property

            Friend ReadOnly Property TargetExecutionContextManager As ActivityExecutionContextManager
                Get
                    Return Me.targetExecutionContextManager
                End Get
            End Property

            Friend ReadOnly Property TargetExecutionInfo As ActivityExecutionContextInfo
                Get
                    Return Me.targetExecutionInfo
                End Get
            End Property


            ' Fields
            Private targetActivity As Activity
            Private targetExecutionContext As ActivityExecutionContext
            Private targetExecutionContextManager As ActivityExecutionContextManager
            Private targetExecutionInfo As ActivityExecutionContextInfo
        End Class
    End Class
End Namespace

